package top.z.template.parse.ast;

import top.z.template.Context;
import top.z.template.Error;
import top.z.template.Template;
import top.z.template.interpreter.AstInterpreter;
import top.z.template.parse.Ast.Expression;
import top.z.template.parse.Ast.Node;
import top.z.template.parse.Span;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**
 * while 语句
 */
public class While extends Node {

    private final Expression condition;
    private final List<Node> body;

    public While(Span span, Expression condition, List<Node> body) {
        super(span);
        this.condition = condition;
        this.body = body;
    }

    public Expression getCondition() {
        return condition;
    }

    public List<Node> getBody() {
        return body;
    }

    @Override
    public Object evaluate(Template template, Context context, OutputStream out) throws IOException {
        context.push();
        while (true) {
            Object condition = getCondition().evaluate(template, context, out);
            if (!(condition instanceof Boolean)) {
                throw Error.error("Expected a condition evaluating to a boolean, got " + condition, getCondition().getSpan());
            }
            if (!((Boolean) condition)) {
                break;
            }
            Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), template, context, out);
            if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
                break;
            }
            if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
                context.pop();
                return breakOrContinueOrReturn;
            }
        }
        context.pop();
        return null;
    }

}
